<template>
  <div id="businessGis">
    <gaode :options="option" @mapcreated="mapcreated">
      <p slot="infoContent">
        高德地图示例<br/>
        也可通过更改baseLayerMode的值，不加载高德默认的底图，而是采用（google/天地图/arcgis）的底图
      </p>
    </gaode>
    <!-- 左边快速定位 -->
    <el-select
      v-model="filterNodeId"
      filterable
      clearable
      value-key="nodeId"
      placeholder="请选择站点"
      class="topo-btn-left"
    >
      <el-option
        v-for="item in stationList"
        :key="item.nodeId"
        :label="item.label"
        :value="item.nodeId"
      />
    </el-select>
    <el-button type="primary" @click="updateMap" class="topo-btn-right">刷新</el-button>
    <!-- 关系线hover时显示 -->
    <el-card v-if="hoverProp" class="edgesTooltip" :style="hoverPosition">
      <ul>
        <li>纤芯：{{ fiberInfo.fiberNum }}</li>
        <li>业务纤芯：{{ fiberInfo.bizNum }}</li>
        <li>空闲纤芯：{{ fiberInfo.idleNum }}</li>
        <li>业务故障纤芯：{{ fiberInfo.damage }}</li>
        <li>备用纤芯：{{ fiberInfo.backUp }}</li>
        <li>进行中纤芯：{{ fiberInfo.processNum }}</li>
      </ul>
    </el-card>
  </div>
</template>
<script>
import { mapGetters } from "vuex";
import mixin from "./mixin";
import { getParentsById } from "@/utils/common";
import Gaode from "@/components/gaode-gis";
export default {
  components: {
    Gaode,
  },
  mixins: [mixin],
  data() {
    return {
      map: null,
      AMap: null,
      hawkEye: null,
      markerList: [],
      BezierCurveList: [],
      textMarker: null, // 文本标注
      cluster: null, // 点聚合
      bezierCurveLayerGroup: null, // 连线群组
      currentPolyLine: {},
      polylineEditor: null,
      clusterTip: false,
      clusterCount: 0,
      markerLayer: null, // 站点覆盖物集合
      dragList: [],
      addShow: false,
      center: []
    };
  },
  computed: {
    option() {
      return {
        options: {
          zoom: 11,
          zooms: [3, 20],
          center: [104.065739, 30.657478],
          mapStyle: "amap://styles/darkblue", // 地图样式
          features: ["bg", "road"]
        },
        tools: true,
        controls: [],
        fullScreen: 'map',
        baseLayerMode: '', // google/tdt/arcgis
        mapType: 'vector',
        popInfo: true
      };
    },
    ...mapGetters(["regionTree"]),
  },
  mounted() {
    this.gisHeight = document.getElementById("businessGis").offsetHeight; // gis地图高度
  },
  methods: {
    // 高德地图类-AMap, 组件里new出来的高德地图实例-map
    async mapcreated({ AMap, map }) {
      this.map = map;
      this.AMap = AMap;
      this.map.addControl(new this.AMap.Scale()) // 添加比例尺
      this.addMapMenu() // map添加右键菜单
      this.changeTheme() // 设置地图颜色
      await this.getTopos()
      // 找一个有经纬度的站点作为地图新的中心点
      const hasLonLat = this.stationList.find(
        (i) => i.longitude && i.latitude
      )
      if (hasLonLat) {
        this.center = [hasLonLat.longitude, hasLonLat.latitude]
        this.map.setCenter(this.center, true)
      }
      this.init()
      this.map.on('zoomend', (e) => {
        this.init()
      })
    },
    init() {
      if (this.map.getZoom() < 10) {
        // 渲染点聚合
        !this.cluster && this.addMarkerCluster() // 添加点聚合
        this.markerLayer && this.markerLayer.hide()
        this.bezierCurveLayerGroup && this.bezierCurveLayerGroup.hide()
      } else {
        // 正常渲染站点和光缆
        !this.markerLayer && this.addMarker()
        this.markerLayer && this.markerLayer.show()
        !this.bezierCurveLayerGroup && this.addBezierCurve()
        this.bezierCurveLayerGroup && this.bezierCurveLayerGroup.show()
        // 把点聚合干掉
        if (this.cluster) {
          setTimeout(() => {
            this.cluster.setMap(null)
            this.cluster = null
          })
        }
      }
    },
    // 添加鹰眼
    addHawkEye() {
      if (this.hawkEye) this.hawkEye.hide()
      this.hawkEye = new this.AMap.HawkEye({
        mapStyle: this.map.getMapStyle(),
        borderWidth: '1px',
        borderColor: '#409EFF',
        width: this.map.getContainer().offsetWidth * 0.2 + 'px',
        height: this.map.getContainer().offsetHeight * 0.2 + 'px',
        offset: [4, 4]
      })
      this.map.addControl(this.hawkEye) // 添加鹰眼
    },
    // 在地图上添加覆盖物
    addMarker() {
      this.stationList.forEach((i) => {
        const color =
          i.status === 'DAMAGE' ? '#409EFF' : 'red'
        if (!i.longitude || !i.latitude) return
        const marker = new this.AMap.Marker({
          // map: this.map,
          clickable: true,
          draggable: true,
          position: [i.longitude, i.latitude],
          anchor: 'center', // 点标记位置
          content: `<div class="marker">
              <i class="marker-icon iconfont icon-AFSa-141" style="color: ${color};"></i>
              <span class="marker-label" style="color: ${color};">${i.label}</span>
            </div>`,
          extData: {
            nodeId: i.nodeId,
            type: i.type,
            label: i.label,
            color: color
          } // 自定义属性，存放自己需要的数据
        })
        this.addMarkerMenu(marker)
        this.markerList.push(marker)
      })
      this.markerLayer = new this.AMap.OverlayGroup(this.markerList) // 新增一个覆盖物图层，把marker放到此图层上
      this.map.add(this.markerLayer)
    },
    // 添加点聚合
    addMarkerCluster() {
      const points = [];
      // 过滤出所有站点的经纬度
      this.stationList.forEach((i) => {
        const color = i.status === "DAMAGE" ? "red" : "#409EFF";
        if (!i.longitude || !i.latitude) return;
        points.push({
          lnglat: [i.longitude, i.latitude],
          data: {
            nodeId: i.nodeId,
            type: i.type,
            label: i.label,
            color: color,
          },
        });
      });
      this.cluster = new this.AMap.MarkerCluster(this.map, points, {
        maxZoom: 10, // 设置地图缩放等级为10时，显示点聚合
        gridSize: 60, // 聚合网格像素大小
        renderClusterMarker: this.renderClusterMarker, // 自定义聚合点样式
        renderMarker: this.renderMarker, // 自定义非聚合点样式
      });
    },
    renderClusterMarker(context) {
      console.log("聚合内部点个数", context.count);
      context.marker.setContent(
        `<div class="marker cluster-marker">
                <span class="marker-label" style="color: #409EFF;">${context.count}</span>
                <i class="marker-icon el-icon-location" style="color: #409EFF;"></i>
              </div>`
      );
      // 如果地图上存在汇聚点且存在弧线，此时就需要删除弧线
      if (
        this.map.getZoom() < (this.cluster && this.cluster.getMaxZoom()) &&
        this.BezierCurveList.length
      ) {
        this.bezierCurveLayerGroup.removeOverlays(this.BezierCurveList);
        this.bezierCurveLayerGroup = null;
        this.BezierCurveList = [];
      }
    },
    renderMarker(context) {
      const extData = context.data[0].data;
      const content = `<div class="marker">
                <i class="marker-icon iconfont icon-AFSa-141" style="color: ${extData.color};"></i>
                <span class="marker-label" style="color: ${extData.color};">${extData.label}</span>
              </div>`;
      context.marker.setContent(content);
      context.marker.setExtData(extData);
      context.marker.setCursor("pointer");
      context.marker.setAnchor("top-center");
      context.marker.setClickable(true);
      context.marker.setDraggable(true)
      this.addMarkerMenu(context.marker); // 给站点添加右键菜单
      // console.log(context)
      const index = this.markerList.findIndex(
        (i) => extData.nodeId === i._opts.extData.nodeId
      );
      // 添加点聚合以后移动地图或缩放地图，都会触发点的重绘，地图会自动擦除之前绘制的点，不用再另外调用marker.remove()或marker.setMap(null)
      if (index !== -1) {
        // delete this.markerList.splice(1, index)[0];
      }
      this.markerList.push(context.marker);

      // 如果地图上没有聚合点且还没有画过弧线，就显示站点间连线
      // console.log('点出现', this.map.getZoom(), this.cluster && this.cluster.getMaxZoom(), this.BezierCurveList)
      // if (
      //   this.map.getZoom() > (this.cluster && this.cluster.getMaxZoom()) &&
      //   !this.BezierCurveList.length
      // ) {
      //   this.bezierCurveLayerGroup = null;
      //   this.addBezierCurve(); // 添加光缆
      //   this.addMouseEvent(); // 给光缆添加hover事件
      //   this.addLineMenu(); // 给光缆添加右键菜单
      // }
    },
    // 给站点添加菜单
    addMarkerMenu(marker) {
      // 添加左键菜单
      const contextMenu = new this.AMap.ContextMenu();
      contextMenu.addItem(
        '关联业务',
        (e) => {
          console.log(this.currentNode)
        },
        0
      );
      contextMenu.addItem(
        '故障业务',
        (e) => {
          console.log(this.currentNode)
        },
        1
      );
      contextMenu.addItem(
        '关联路由',
        (e) => {
          console.log(this.currentNode)
        },
        2
      );
      contextMenu.addItem(
        '故障路由',
        (e) => {
          console.log(this.currentNode)
        },
        3
      );
      contextMenu.addItem(
        '设备详情',
        (e) => {
          console.log(this.currentNode)
        },
        4
      );
      contextMenu.addItem(
        '智能开通',
        (e) => {
          console.log(this.currentNode)
        },
        5
      );
      marker.on("click", (e) => {
        contextMenu.open(this.map, e.lnglat);
        this.currentNode = e.target._opts.extData;
      });
      // 添加右键-修改区域
      const contextMenu2 = new this.AMap.ContextMenu();
      contextMenu2.addItem(
        '修改站点',
        (e) => {
          const regionList =
            getParentsById(
              this.regionTree,
              this.currentNode.nodeId,
              "regionId"
            ) || [];
          this.stationInfo = regionList[0];
          this.editShow = !this.editShow;
        },
        0
      );
      marker.on("rightclick", (e) => {
        contextMenu2.open(this.map, e.lnglat);
        this.currentNode = e.target._opts.extData;
      });
      // 站点开始拖拽，隐藏和站点有关的连线
      marker.on('dragstart', e => {
        const currentNodeId = e.target.getExtData().nodeId
        this.BezierCurveList.forEach(i => {
          const polylineData = i.getExtData()
          if (polylineData.fromNodeId === currentNodeId || polylineData.toNodeId === currentNodeId) {
            i.hide() // 隐藏折线
          }
        })
      })
      // 站点拖拽结束
      marker.on('dragend', (e) => {
        const index = this.dragList.findIndex(
          (i) => e.target._opts.extData.nodeId === i.target._opts.extData.nodeId
        )
        if (index !== -1) delete this.dragList.splice(index, 1)[0]
        this.dragList.push(e)
        // 拖拽完成自动保存新的机房位置
        this.saveGis()
      })
    },
    // 在地图上添加弧线
    addBezierCurve() {
      this.cableList.forEach((i, index) => {
        const color =
          i.status === "DAMAGE" ? 'red' : '#409EFF';
        // 如果两个站点里有多条光缆，判断每条光缆在两个站点之间，是第几条，用这个计算偏移量
        const offset =
          this.edges
            .filter(
              (j) =>
                (j.fromNodeId === i.fromNodeId && j.toNodeId === i.toNodeId) ||
                (j.fromNodeId === i.toNodeId && j.toNodeId === i.fromNodeId)
            )
            .findIndex((j) => j.id === i.id) + 1;
        let path = [];
        if (
          i.fromLngLat[0] === i.toLngLat[0] &&
          i.fromLngLat[1] === i.toLngLat[1]
        ) {
          // 如果自连(站点内部存在光缆)，就多增加2个控制点，好画弧线
          const middlePort = this.addMidlePort(
            [i.fromLngLat, i.toLngLat],
            0.1 * offset
          );
          path = [
            middlePort[0],
            [...middlePort[1], ...middlePort[2], ...middlePort[3]],
          ];
        } else {
          // 两个站点之间画弧线，利用中心点作为控制点，再给中心点加上偏移量，防止如果有多条光缆，互相覆盖
          const p1 = new this.AMap.LngLat(i.fromLngLat[0], i.fromLngLat[1])
          const p2 = new this.AMap.LngLat(i.toLngLat[0], i.toLngLat[1])
          let distance = Math.round(p1.distance(p2))
          // 如果单根光缆超过200公里，就按照200公里算
          if (distance > 100000) distance = 100000
          // 以200米为一个基准，两个站点点距离每增加200米，经纬度变化就是0.00025的倍数，以此来计算偏移量
          const centerPointLng1 =
            offset % 2 === 0
              ? i.centerPoint.lng + Math.round(distance / 200) * 0.00025 ** offset
              : i.centerPoint.lng - Math.round(distance / 200) * 0.00025 ** offset
          const centerPointLat1 =
            offset % 2 === 0
              ? i.centerPoint.lat + Math.round(distance / 200) * 0.00025 ** offset
              : i.centerPoint.lat - Math.round(distance / 200) * 0.00025 ** offset
          // 画贝塞尔曲线的路径
          // path = [
          //   [i.fromLngLat[0], i.fromLngLat[1]],
          //   [centerPointLng1, i.centerPoint.lat], [centerPointLng1, centerPointLat1], [i.toLngLat[0], i.toLngLat[1]] // 控制点和途经点
          // ]

          path = [
            [i.fromLngLat[0], i.fromLngLat[1]],
            [centerPointLng1, centerPointLat1, i.toLngLat[0], i.toLngLat[1]] // 控制点和途经点
          ]
        }
        const BezierCurve = new this.AMap.BezierCurve({
          path: path,
          strokeColor: color,
          clickable: true,
          lineJoin: "round",
          cursor: "pointer",
          strokeWeight: 3, // 线宽
          strokeOpacity: 1, // 透明度
          extData: {
            id: i.id,
            label: i.label,
            subInfo: i.subInfo,
            color: color,
            fromNodeId: i.fromNodeId,
            toNodeId: i.toNodeId
          }, // 自定义属性，存放自己需要的数据
        });
        this.BezierCurveList.push(BezierCurve);
      });
      this.bezierCurveLayerGroup = new this.AMap.OverlayGroup(
        this.BezierCurveList
      ); // 新增一个覆盖物图层，把弧线放到此图层上
      this.map.add(this.bezierCurveLayerGroup);
      // this.map.setFitView(this.BezierCurveList) // 缩放地图到合适的视野级别
      this.addMouseEvent()
      this.addLineMenu()
    },
    // 给光缆添加鼠标悬浮和离开事件
    addMouseEvent() {
      this.BezierCurveList.forEach((i) => {
        i.on("mouseover", (e) => {
          // console.log(e)
          e.target.setOptions({
            strokeColor: "#ccc",
          });
          // 给光缆添加名字
          this.addText(
            {
              lng: e.lnglat.lng,
              lat: e.lnglat.lat,
              x: e.pixel.x,
              y: e.pixel.y,
              ...e.target._opts.extData,
            },
            "HOVER"
          );
        });
        i.on("mouseout", (e) => {
          e.target.setOptions({
            strokeColor: e.target._opts.extData.color,
          });
          this.addText(null, "LEAVE");
        });
      });
    },
    addLineMenu() {
      const contextMenu = new this.AMap.ContextMenu();
      contextMenu.addItem(
        '光缆详情',
        (e) => {
          this.cableDetailShow = !this.cableDetailShow;
        },
        0
      );
      this.BezierCurveList.forEach((i, index) => {
        i.on("rightclick", (e, i) => {
          contextMenu.open(this.map, e.lnglat);
          // contextMenuPositon = e.lnglat
          this.currentEdge = e.target._opts.extData;
          // 点击了右键，就把悬浮框隐藏
          this.hoverProp = false;
        });
      });
    },
    // 地图添加右键菜单
    addMapMenu() {
      const content = []
      content.push(
        `<el-button class="el-button el-button--primary el-button--mini" onclick="addShow()">新增站点</el-button>`
      )
      const contextMenu = new this.AMap.ContextMenu({
        isCustom: true,
        content: content.join('')
      })
      this.map.on('rightclick', (e) => {
        contextMenu.open(this.map, e.lnglat)
        this.stationInfo = {
          operateType: 'GIS',
          regionType: 'STATION',
          longitude: e.lnglat.lng,
          latitude: e.lnglat.lat
        }
      })
      window.addShow = () => {
        this.addShow = !this.addShow
      }
    },
    changeTheme() {
      // console.log(this.getThemeList)
      // console.log(this.getTheme)
      switch (this.getTheme) {
      case 'dark-theme':
        this.map.setMapStyle('amap://styles/darkblue')
        break
      case 'red-theme':
        this.map.setMapStyle('amap://styles/macaron')
        break
      case 'green-theme':
        this.map.setMapStyle('amap://styles/whitesmoke')
        break
      case 'blue-theme':
        this.map.setMapStyle('amap://styles/blue')
        break
      }
      this.addHawkEye()
    },
    // 在地图上添加文本标记
    addText(data, mouseStatus) {
      this.hoverProp = false
      if (mouseStatus === 'HOVER') {
        this.hoverProp = true
        this.fiberInfo = data.subInfo
        this.hoverPositionLeft = data.x + 20
        this.hoverPositionTop = data.y + 20
        this.textMarker = new this.AMap.Text({
          text: data.label,
          position: [data.lng, data.lat],
          style: {
            color: data.color
          },
          anchor: 'bottom-right'
        })
        this.map.add(this.textMarker)
      } else if (mouseStatus === 'LEAVE') {
        this.fiberInfo = {}
        this.hoverPositionLeft = 0
        this.hoverPositionTop = 0
        if (this.textMarker) {
          this.textMarker.remove()
          this.textMarker = null
        }
      }
    },
    // 高亮某个marker
    hightLightMarker(id) {
      const currentMarker = this.markerList.find(i => {
        return i._opts.extData.nodeId === id
      })
      if (!currentMarker) {
        this.$message.error('此站点无经纬度信息!')
        return
      }
      // 更新marker的content
      currentMarker.setContent(
        `<div class="marker">
          <i class="marker-light-icon iconfont icon-AFSa-141" style="color: yellow;"></i>
          <span class="marker-label" style="color: yellow;">${currentMarker._opts.extData.label}</span>
        </div>`
      )
      // 更改地图中心点
      this.map.panTo(currentMarker._position)
    },
    // 移除marker的高亮
    removeHightLightMarker(id) {
      const currentMarker = this.markerList.find(i => {
        return i._opts.extData.nodeId === id
      })
      if (!currentMarker) {
        return
      }
      // 更新marker的content
      currentMarker.setContent(
        `<div class="marker">
          <i class="marker-icon iconfont icon-AFSa-141" style="color: ${currentMarker._opts.extData.color};"></i>
          <span class="marker-label" style="color: ${currentMarker._opts.extData.color};">${currentMarker._opts.extData.label}</span>
        </div>`
      )
    },
    updateMap() {
      // 移除弧线
      this.bezierCurveLayerGroup &&
        this.bezierCurveLayerGroup.removeOverlays(this.BezierCurveList)
      this.BezierCurveList = []
      this.bezierCurveLayerGroup = null
      // 移除点聚合
      this.cluster && this.cluster.setMap(null)
      this.cluster = null
      // 移除所有站点
      this.markerLayer && this.markerLayer.removeOverlays(this.markerList)
      this.markerList = []
      this.markerLayer = null
      // 移除文本标注
      this.textMarker && this.textMarker.remove()
      this.textMarker = null
      this.filterNodeId = ''
      this.hoverPositionLeft = 0
      this.hoverPositionTop = 0

      this.getTopos().then((rsp) => {
        this.init()
      })
    },
    // 根据链路高亮某一组连线
    hoverEdges(data) {
      // 鼠标进入
      data.cableIds.forEach((i) => {
        if (i) {
          this.BezierCurveList.forEach((j) => {
            if (j._opts.extData.id === i) {
              j.setOptions({
                strokeColor:
                  data.type === 'enter' ? 'green' : j._opts.extData.color
              })
            }
          })
        }
      })
    },
    saveGis() {
      console.log(this.dragList)
      this.updateMap() // 更新
      // let promiseArr = []
      // promiseArr = this.dragList.map((i) =>
      //   regionApi.mod({
      //     id: getParentsById(
      //       this.regionTree,
      //       i.target._opts.extData.nodeId,
      //       'regionId'
      //     )[0].id,
      //     regionId: i.target._opts.extData.nodeId,
      //     longitude: i.lnglat.lng,
      //     latitude: i.lnglat.lat
      //   })
      // )
      // Promise.all(promiseArr).then((rsp) => {
      //   if (!rsp.length) return
      //   if (!rsp.some((i) => !i)) {
      //     this.updateMap()
      //   }
      // })
    }
  },
};
</script>
<style lang="scss">
#businessGis {
  position: relative;
  height: 90%;
  .marker {
    text-align: center;
    &-icon {
      font-size: 36px;
    }
    &-light-icon {
      font-size: 40px;
    }
    &-label {
      font-size: 14px;
      font-weight: 600;
    }
  }
  .edgesTooltip {
    position: absolute;
  }
  .open-box {
    position: absolute;
    top: 50px;
    left: 10px;
    width: 400px;
    height: calc(100% - 60px);
    background: rgba($color: #000, $alpha: 0.9);

    label,
    p {
      color: #fff;
      font-size: 14px;
      line-height: 20px;
    }

    .test-progress {
      color: #fff;
    }
  }
}

.topo-btn-left {
  position: absolute;
  left: 20px;
  top: 10px;
  width: auto;
}
.topo-btn-right {
  position: absolute;
  right: 20px;
  top: 100px;
  width: auto;
}
</style>
